package org.andromda.cartridges.gwt.metafacades;

import java.util.Collection;
import java.util.Iterator;

import org.andromda.metafacades.emf.uml2.ParameterFacadeLogic;
import org.andromda.metafacades.uml.AttributeFacade;
import org.andromda.metafacades.uml.DependencyFacade;
import org.andromda.metafacades.uml.Entity;
import org.andromda.metafacades.uml.EntityAttribute;
import org.andromda.metafacades.uml.ModelElementFacade;
import org.andromda.metafacades.uml.ParameterFacade;
import org.andromda.metafacades.uml.ServiceOperation;
import org.andromda.metafacades.uml.ValueObject;
import org.apache.log4j.Logger;

/**
 * MetafacadeLogic implementation for org.andromda.cartridges.gwt.metafacades.GwtProxy.
 * 
 * @see org.andromda.cartridges.gwt.metafacades.GwtProxy
 */
public class GwtProxyLogicImpl extends GwtProxyLogic {

	/**
	 * The logger instance.
	 */
	private static final Logger	logger	= Logger.getLogger( GwtProxyLogicImpl.class );

	public GwtProxyLogicImpl(Object metaObject, String context) {
		super( metaObject, context );
	}

	/**
	 * @see org.andromda.cartridges.gwt.metafacades.GwtProxy#getServiceOperation()
	 */
	@Override
	protected java.lang.Object handleGetServiceOperation() {
		if ( this.getSourceDependencies().size() > 0 ) {
			for ( Iterator i = this.getSourceDependencies().iterator(); i.hasNext(); ) {
				ModelElementFacade targetElement = ( ( DependencyFacade ) i.next() ).getTargetElement();
				logger.debug( "serviceOperation() :: targetElement = " + targetElement.getClass() );
				if ( ( targetElement != null ) && ServiceOperation.class.isAssignableFrom( targetElement.getClass() ) ) {
					logger.debug( "serviceOperation() :: result = " + targetElement );
					return targetElement;
				}
			}
			logger.error( "Cannot find a service operation for " + getName() );
		} else {
			logger.error( "Cannot dependencies for " + getName() );
		}

		return null;
	}

	@Override
	protected String handleGetDtoClass() {
		logger.debug( "getDtoClass() :: Start" );
		Entity relatedEntity = ( Entity ) handleGetRelatedEntity();
		if ( relatedEntity != null ) {
			for ( Iterator i = relatedEntity.getSourceDependencies().iterator(); i.hasNext(); ) {
				ModelElementFacade targetElement = ( ( DependencyFacade ) i.next() ).getTargetElement();
				if ( ( targetElement != null ) && ValueObject.class.isAssignableFrom( targetElement.getClass() ) ) {
					logger.debug( "getDtoClass() :: result =" + targetElement.getFullyQualifiedName() );
					return targetElement.getFullyQualifiedName();
				}
			}
			logger.error( "Cannot find a DTO for " + getName() );
			return null;
		} else {
			return null;
		}
	}

	@Override
	protected String handleGetEntityPrimaryKey() {
		Entity relatedEntity = ( Entity ) handleGetRelatedEntity();
		if ( relatedEntity != null ) {
			Collection identifiers = relatedEntity.getIdentifiers( false );
			for ( Iterator i = identifiers.iterator(); i.hasNext(); ) {
				EntityAttribute targetElement = ( EntityAttribute ) i.next();
				if ( targetElement != null ) {
					return targetElement.getName();
				}
			}
			logger.error( "Cannot find a primary key for the related entity of " + getName() );
			return null;
		} else {
			return null;
		}
	}

	@Override
	protected Object handleGetRelatedEntity() {
		logger.debug( "getRelatedEntity() :: Start" );
		if ( this.getSourceDependencies().size() > 0 ) {
			for ( Iterator i = this.getSourceDependencies().iterator(); i.hasNext(); ) {
				ModelElementFacade targetElement = ( ( DependencyFacade ) i.next() ).getTargetElement();
				if ( ( targetElement != null ) && Entity.class.isAssignableFrom( targetElement.getClass() ) ) {
					logger.debug( "getRelatedEntity() :: result =" + targetElement );
					return targetElement;
				}
			}
			logger.error( "Cannot find a related service for " + getName() );
		} else {
			logger.error( "Cannot dependencies for " + getName() );
		}
		return null;
	}

	@Override
	protected ParameterFacade handleGetSearchCriteriaEntity() {
		ServiceOperation searchOp = ( ServiceOperation ) handleGetServiceOperation();
		Collection arguments = searchOp.getArguments();
		if ( arguments != null ) {
			for ( Iterator i = arguments.iterator(); i.hasNext(); ) {
				ParameterFacadeLogic targetElement = ( ParameterFacadeLogic ) i.next();
				logger.debug( "getSearchCriteriaEntity() :: targetElement = " + targetElement.getClass() + ", name = "
				        + targetElement.getName() );
				if ( ( targetElement != null ) && targetElement.getName().equalsIgnoreCase( "criteria" ) ) {
					logger.debug( "getSearchCriteriaEntity() :: result =" + targetElement.getFullyQualifiedName() );
					return targetElement;
				}
			}
			logger.error( "Cannot find the search criteria entity for " + getName() );
		} else {
			logger.error( "No 'criteria' arguments for " + searchOp.getFullyQualifiedName() );
		}
		return null;
	}

	@Override
	protected String handleGetSearchCriteriaClass() {
		ParameterFacade targetElement = handleGetSearchCriteriaEntity();
		if ( targetElement != null ) {
			return targetElement.getType().getFullyQualifiedName();
		} else {
			logger.error( "Cannot find the search criteria class for " + getName() );
			return null;
		}
	}

	@Override
	protected Object handleGetAsyncService() {
		if ( this.getSourceDependencies().size() > 0 ) {
			for ( Iterator i = this.getSourceDependencies().iterator(); i.hasNext(); ) {
				ModelElementFacade targetElement = ( ( DependencyFacade ) i.next() ).getTargetElement();
				logger.debug( "getAsyncService() :: targetElement = " + targetElement.getClass() );
				if ( ( targetElement != null ) && GwtService.class.isAssignableFrom( targetElement.getClass() ) ) {
					logger.debug( "getAsyncService() :: result = " + targetElement );
					return targetElement;
				}
			}
			logger.error( "Cannot find a async service for " + getName() );
		} else {
			logger.error( "Cannot dependencies for " + getName() );
		}
		return null;
	}

	@Override
	protected String handleGetAsyncServiceFullQualifiedName() {
		GwtService service = ( GwtService ) handleGetAsyncService();
		if ( service != null ) {
			return service.getFullyQualifiedName();
		} else {
			logger.error( "Cannot find a async service full qualified name for " + getName() );
			return null;
		}
	}

	@Override
	protected ValueObject handleGetRelatedDTO() {
		Entity relatedEntity = ( Entity ) handleGetRelatedEntity();
		if ( relatedEntity.getSourceDependencies().size() > 0 ) {
			for ( Iterator i = relatedEntity.getSourceDependencies().iterator(); i.hasNext(); ) {
				ModelElementFacade targetElement = ( ( DependencyFacade ) i.next() ).getTargetElement();
				logger.debug( "getRelatedDTO() :: targetElement = " + targetElement.getClass() );
				if ( ( targetElement != null ) && ValueObject.class.isAssignableFrom( targetElement.getClass() ) ) {
					logger.debug( "getRelatedDTO() :: result = " + targetElement );
					return ( ValueObject ) targetElement;
				}
			}
			logger.error( "Cannot find a related DTO for " + getName() );
		} else {
			logger.error( "Cannot dependencies for " + getName() );
		}
		return null;
	}

	@Override
	protected String handleGetColumnModel() {
		ValueObject relatedDTO = handleGetRelatedDTO();
		if ( relatedDTO != null ) {
			StringBuffer result = new StringBuffer();
			Collection attributes = relatedDTO.getAttributes( true );

			for ( Iterator i = attributes.iterator(); i.hasNext(); ) {
				AttributeFacade attribute = ( AttributeFacade ) i.next();
				result.append( "getColumnConfig( \"" ).append( attribute.getName() ).append( "\", \"" ).append(
				        attribute.getName() ).append( "\" )" );
				if ( i.hasNext() ) {
					result.append( ",\n\t\t       " );
				}
			}
			return result.toString();
		} else {
			logger.error( "Cannot generate the columnModel because no DTO was found for " + getName() );
			return null;
		}
	}

	@Override
	protected Collection handleGetSearchCriteriaAttributes() {
		// TODO Auto-generated method stub
		return null;
	}

}